import json
import os
import sys
import time
import re
import zipfile
from datetime import datetime, timedelta
import winreg
import psutil
import requests
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import redis
import settings
import random


def get_server_chrome_versions():
    '''return all versions list'''
    versionList=[]
    url="http://npm.taobao.org/mirrors/chromedriver/"
    rep = requests.get(url).text
    result = re.compile(r'\d.*?/</a>.*?Z').findall(rep)
    for i in result:                                 # 提取时间
        version = re.compile(r'.*?/').findall(i)[0]         # 提取版本号
        versionList.append(version[:-1])                  # 将所有版本存入列表
    return versionList


def download_chromedriver(download_url):
    '''下载文件'''
    file = requests.get(download_url)
    with open("chromedriver.zip", 'wb') as zip_file:        # 保存文件到脚本所在目录
        zip_file.write(file.content)
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + '\t\t解压成功')


def unzip_driver(path):
    '''解压Chromedriver压缩包到指定目录'''
    f = zipfile.ZipFile("chromedriver.zip",'r')
    for file in f.namelist():
        f.extract(file, path)


def update_chromedriver(chrome_version, chromedriver_path):
    url = 'http://npm.taobao.org/mirrors/chromedriver/'
    version_list = get_server_chrome_versions()
    download_url = ""
    if chrome_version in version_list:
        download_url = f"{url}{chrome_version}/chromedriver_win32.zip"
    else:
        for version in version_list:
            if version.startswith(str(chrome_version.split(".")[0])):
                download_url = f"{url}{version}/chromedriver_win32.zip"
                break
        if download_url == "":
            print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t暂无法找到与chrome兼容的chromedriver版本，请在http://npm.taobao.org/mirrors/chromedriver/ 核实。")
            return

    download_chromedriver(download_url=download_url)
    unzip_driver(chromedriver_path)
    os.remove("chromedriver.zip")
    print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + '\t\t更新后的Chromedriver版本为：', get_chromedriver_version(chromedriver_path))


def get_chromedriver_version(path):
    try:
        if os.path.exists(path + "/chromedriver.exe"):
            version = os.popen(path + "/chromedriver.exe" + ' --version').read()
            return version.split(' ')[1].split('.')[0]
        else:
            print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\tChromedriver文件不存在！")
            return None
    except Exception as e:
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t获取Chromedriver版本出现错误！")
        print(e)
        return None


def get_chrome_version():
    try:
        key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Google\Chrome\BLBeacon')
        version, types = winreg.QueryValueEx(key, 'version')
        return version.split('.')[0]
    except Exception as e:
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t获取Chrome浏览器版本出现错误！")
        print(e)
        return None


def get_target_url():
    try:
        target = ['china', 'russia', 'usa', 'england', 'germany', 'france',
                  'beijing', 'berlin', 'paris', 'london', 'moscow', 'washington']
        rand = int(random.random() * 500 + 100)
        since_date = (datetime.now() - timedelta(days=rand)).strftime("%Y-%m-%d")
        until_date = (datetime.now() - timedelta(days=rand - 1)).strftime("%Y-%m-%d")
        url = str.format('https://twitter.com/search?q={0}%20since%3A{1}%20until%3A{2}&src=typed_query&f=live',
                         target[rand % len(target)], since_date, until_date)
        return url
    except Exception as e:
        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t获取目标URL出现错误！")
        print(e)
        return None


def produce_token(host, port, request_token_queue_name, token_queue_name, chromedriver_path):
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument('--headless')  # 无界面
    chrome_options.add_argument('--no-sandbox')  # 解决DevToolsActivePort文件不存在报错问题
    chrome_options.add_argument('--disable-gpu')  # 禁用GPU硬件加速。如果软件渲染器没有就位，则GPU进程将不会启动。
    chrome_options.add_argument('--disable-dev-shm-usage')
    chrome_options.add_experimental_option('w3c', False)
    caps = DesiredCapabilities.CHROME
    caps['loggingPrefs'] = {'performance': 'ALL'}

    redis_client = redis.Redis(host=host, port=port)
    redis_client.delete(token_queue_name)
    print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\ttoken producer start.............................")

    while True:
        try:
            try:
                chrome_version = get_chrome_version()
                if chrome_version is None:
                    print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t未检测到Chrome版本号，请检查是否已安装Chrome浏览器")
                    return
                if not os.path.exists(chromedriver_path):
                    os.mkdir(chromedriver_path)
                chromedriver_version = get_chromedriver_version(chromedriver_path)
                if chromedriver_version is None:
                    print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t未检测到Chromedriver版本号")
                    update_chromedriver(chrome_version, chromedriver_path)
                    continue
                if str(chrome_version) != str(chromedriver_version):
                    print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t【chrome】和【chromedriver】版本不匹配，正在更新Chromedriver！")
                    update_chromedriver(chrome_version, chromedriver_path)
                    continue
            except Exception as e:
                print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t检查Chrome和Chromedriver出现错误")
                print(e)
                time.sleep(120)

            if redis_client.llen(request_token_queue_name) > 0:
                request = json.loads(redis_client.rpop(request_token_queue_name))
                if settings.get_csrf_token == request:
                    while True:
                        try:
                            driver = webdriver.Chrome(executable_path=chromedriver_path + "/chromedriver.exe", desired_capabilities=caps,
                                                      options=chrome_options)
                            break
                        except Exception as e:
                            print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\tERROR:driver = webdriver.Chrome()")
                            print(e)
                            for proc in psutil.process_iter():
                                # 检查chromedriver，如果存在则杀死进程重新启动
                                if "chromedriver" in proc.name():
                                    proc.kill()
                            time.sleep(60)

                    while True:
                        try:
                            driver.delete_all_cookies()
                            driver.get(get_target_url())
                            time.sleep(10)
                            # 可能会出现这个问题，需要刷新页面
                            if "Something went wrong, but don’t fret" in driver.page_source:
                                driver.refresh()
                                time.sleep(15)
                            break
                        except Exception as e:
                            print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\tERROR:driver.get(url)")
                            print(e)
                            time.sleep(60)

                    # 刷新后再次出现这个问题，放弃该url
                    if "Something went wrong, but don’t fret" in driver.page_source:
                        redis_client.lpush(request_token_queue_name, json.dumps(request))
                        continue

                    log = driver.get_log('performance')
                    token_dict = {}
                    csrf = set()
                    guest = set()
                    pattern = r"x-csrf-token.:.[\w|\d]{1,}"
                    matches = re.findall(pattern, str(log))
                    # print(log)
                    for i in range(len(matches)):
                        csrf.add(matches[i])
                    pattern = r"x-guest-token.:.\d{1,}"
                    matches = re.findall(pattern, str(log))
                    for i in range(len(matches)):
                        guest.add(matches[i])
                    driver.quit()
                    if len(csrf) > 0 and len(guest) > 0:
                        min = len(csrf) if len(csrf) <= len(guest) else len(guest)
                        for i in range(min):
                            token_dict['csrf'] = str(csrf.pop()).split('":"')[1]
                            token_dict['guest'] = str(guest.pop()).split('":"')[1]
                            print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t" + str(token_dict))
                            redis_client.lpush(token_queue_name, json.dumps(token_dict))
                    else:
                        print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t未获取到csrf和guest，请检查！")
                        redis_client.lpush(request_token_queue_name, json.dumps(request))
                        time.sleep(10)
                else:
                    print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t未知命令！" + str(request))
            else:
                time.sleep(10)
        except Exception as e:
            print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\t\t读写redis出错！")
            print(e)
            time.sleep(60)


if __name__ == '__main__':
    chromedriver_path = sys.path[0] + '/tools'

    produce_token(settings.redis_host, settings.redis_port, settings.request_token_queue_name,
                   settings.token_queue_name, chromedriver_path)
